К сожалению, я не могу похвастаться авторством на идею этого замечательного примера. Идея принадлежит Дэну Стайнману (Dan Steinman). У него же взяты и картинки. Сама же программа была основательно переработана. Например, у Дэна, солнце было неподвижным и т.д.
В чем здесь суть? Дело в том, что солнце вращается по элиптической орбите вокруг некоторого центра. Замля, в свою очередь, вращается вокруг солнца, также по элиптической орбите. Наконец, Луна вращается вокруг Земли, опять же, по элиптической орбите. И все это вращается одновременно! Траектория Земли, довольно замысловата, а уж о траектории Луны и говорить нечего!
Как же удается справиться с таким сложным движением? Это было бы действительно трудно, если бы не идея использования объектов. Смотрите внимательно, собака зарыта именно здесь. Поняв это, Вы поймете все остальное. Итак:
Повторю по другому. Система в целом просто вращается по эллипсу. Если мы влезем внутрь этой системы (и будем двигаться по эллипсу вместе с ней), то мы обнаружим, что у нее два дочерних элемента - неподвижное солнце и система Земля-Луна. Последняя, внутри своего родителя, тоже просто вращается по эллипсу. Влезем внутрь системы Земля-Луна (двигаемся вместе с ней) и увидим, что внутри у нее имеется неподвижная Земля и, вращающаяся по обыкновенному эллипсу Луна.
Таким образом мы не связываемся со сложными траекториями. Нам удалось разложить сложное движения на три простых вращения по эллиптической траектории. Все эти три вращения может выполнять одна-единственная несложная программа. Что, кстати, в данном примере и делается.
Если Вам понятно вышеизложенное, то все остальное - дело техники, причем не такой уж и сложной тезники.
Система движущихся тел задается следующими тэгами:
<SPAN ID="allSpan" STYLE="position:absolute;left:0;top:80;width:336;height:316;"> <SPAN ID="sunSpan" STYLE="position:absolute;left:131;top:90;width:71;"> <IMG SRC="../images/sun.gif" WIDTH=71 HEIGHT=71 BORDER=0> </SPAN> <SPAN ID="earthMoonSpan" STYLE="position:absolute;left:232;top:72;width:100;height:100;"> <SPAN ID="earthSpan" STYLE="position:absolute;z-index:2;left:34;top:34;width:32;height:32;"> <IMG SRC="../images/earth.gif" WIDTH=32 HEIGHT=32 BORDER=0> </SPAN> <SPAN ID="moonSpan" STYLE="position:absolute;left:80;top:40;width:20;height:20;"> <IMG SRC="../images/moon.gif" WIDTH=20 HEIGHT=20 BORDER=0> </SPAN> </SPAN> </SPAN>
Здесь, "система в целом" - allSpan имеет двух потомков - Солнце (sunSpan) и систему Земля-Луна (earthMoonSpan). Последняя, в свою очередь, тоже имеет двух потомков - Землю (earthSpan) и Луну (moonSpan). Все, как было обсуждено выше.
После загрузки документа запускается программа init(), как обычно.
function init() { var NN = (navigator.appName == "Netscape"); speed = 20; moon = (NN) ? document.layers["allSpan"].document.layers["earthMoonSpan"].document.layers["moonSpan"] : document.all["moonSpan"].style; earth = (NN) ? document.layers["allSpan"].document.layers["earthMoonSpan"].document.layers["earthSpan"] : document.all["earthSpan"].style; earthMoon = (NN) ? document.layers["allSpan"].document.layers["earthMoonSpan"] : document.all["earthMoonSpan"].style; sun = (NN) ? document.layers["allSpan"] : document.all["allSpan"].style; initObject(earthMoon,125,1.5,20,1,1,1); initObject(moon,16,4,0,-1,1,2); initObject(sun,75,1,180,1,1,2); moveObjects(); }
В ней определяется переменная NN (true, если имеем дело с Netscape), переменная speed - значение задержки анимации и четыре переменные - объекты содержащие свойства left и top для элементов: sun - система в целом, moon - Луна, earth - Земля и earthMoon - система Земля-Луна. Вообще-то, если бы мы только вращали тела, то объект Земля, нам не был бы нужен - она ведь неподвижна внутри своего родителя. Однако, мы будем использовать его для того, чтобы обработать "заход Луны за Землю" (видели, она там немножко заходит, то сверху, то снизу).
Далее, для каждого движущегося объекта вызывается функция initObject(). Все, что она делает, это добавляет к объекту целый ряд свойств. Эти свойства - суть параметры орбиты. Если Вы посмотрите на эту функцию и на коротенькую функцию circleMove(), которая, собственно и занимается движением, то Вы легко поймете, что означают все эти параметры. Разумеется, неплохо бы, при этом, помнить уравнение эллипса :-)
function initObject(obj,radius,angleinc,anglestart, direction,vertical,horizontal) { obj.radius = radius; obj.angleinc = angleinc; obj.anglestart = anglestart; obj.angle = anglestart; obj.direction = direction; obj.vertical = vertical; obj.horizontal = horizontal; obj.centerX = parseInt(obj.left) - horizontal*radius*Math.cos(anglestart*Math.PI/180); obj.centerY = parseInt(obj.top) + vertical*radius*Math.sin(anglestart*Math.PI/180); obj.move = circleMove; } function circleMove() { with (this) { angle += direction*angleinc; left = centerX + horizontal*radius*Math.cos(angle*Math.PI/180); top = centerY - vertical*radius*Math.sin(angle*Math.PI/180); } }
Осталось рассмотреть функцию moveObjects(), которая работает пятьесят раз в секунду. Она вызывает circleMove() для отработки движения объектов и управляет zIndex Земли и Луны.
var sunDelay = true; function moveObjects() { earthMoon.move(); moon.move(); sunDelay = !sunDelay; if (sunDelay) sun.move(); if (parseInt(moon.top) > parseInt(earth.top)) { if (moon.zIndex != 1) moon.zIndex = 1; } else { if (moon.zIndex != 3) moon.zIndex = 3; } setTimeout("moveObjects()",speed) }
Манипуляции с переменной sunDelay служат для того, чтобы Солнце двигалось в два раза реже, чем все остальное, а то оно летает неприлично быстро для светила.
Вот, собственно и весь пример.